package com.tm.chargecar.conf;

import cn.hutool.extra.servlet.ServletUtil;
import com.alibaba.fastjson.JSON;
import com.tm.chargecar.entity.OperationLogEntity;
import com.tm.chargecar.service.LogService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author lichuan
 */
//7.定义用来记录用户操作日志的切面类
@Aspect
@Component
public class OperationLogAspect {
    @Autowired
    private LogService logService;
    /**
     * 设置操作日志切入点，在注解的位置切入代码
     */
    @Pointcut("@annotation(com.tm.chargecar.conf.OperationLog)")
    public void operationLogPointCut() {
    }

    /**
     * 定义环绕通知
     * 1. 环绕通知需要携带ProceedingJoinPoint类型的参数
     * 2. 环绕通知类似于动态代理的全过程ProceedingJoinPoint类型的参数可以决定是否执行目标方法
     * 3. 且环绕通知必须有返回值，返回值即目标方法的返回值
     */
    @Around("operationLogPointCut()")
    public Object around(ProceedingJoinPoint joinPoint) {
        Object result =null;
        //获取系统当前时间
        long beginTime  = System.currentTimeMillis();
        try {
            //执行目标方法
            result=joinPoint.proceed();
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
        //获取当前系统的毫秒值
        long endTime   = System.currentTimeMillis();
        // 获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest  request =(HttpServletRequest) requestAttributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);
        String clientIP = ServletUtil.getClientIP(request);
        OperationLogEntity logEntity = new OperationLogEntity();
        logEntity.setIp(clientIP);
        //获取目标方法执行时间
        long usageTime=endTime-beginTime;
        logEntity.setUsageTime((int) usageTime);
        // 从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //获取操作
        Method method = signature.getMethod();
        OperationLog operationLog = method.getAnnotation(OperationLog.class);
        if(operationLog!=null){
            logEntity.setModuleName(operationLog.operationModule());
            logEntity.setDescription(operationLog.description());
            logEntity.setOperationType(operationLog.operationType().getOperationType());
        }
        //获取请求的类名
        String calssName = joinPoint.getTarget().getClass().getName();
        //获取请求的方法名
        String methodName = method.getName();
        methodName=calssName+"."+methodName;
        //请求方式
        logEntity.setMethod(methodName);
        //请求的参数
        Map<String, String> paramMap = ServletUtil.getParamMap(request);
        //将参数所在的数组转成josn
        String requestParams = JSON.toJSONString(paramMap);
        //请求参数
        logEntity.setRequestParams(requestParams);
        //返回结果
        String response = JSON.toJSONString(result);
        logEntity.setResponseParams(response);
        //请求用户id

        logEntity.setOperator("admin");
        // 请求URL
        logEntity.setUrl(request.getRequestURL().toString());
        logEntity.setUri(request.getRequestURI());
        // 创建时间
        logEntity.setCreateTime(new Date());
        System.out.println(logEntity);
        logService.addUser(logEntity);
        return result;
    }

    /**
     * 转换request 请求参数
     * @param parameterMap request获取的参数数组
     */
    public Map<String, String> convertParameterMap(Map<String, String[]> parameterMap) {
        Map<String, String> convertParameterMap = new HashMap<>();
        for (String key : parameterMap.keySet()) {
            convertParameterMap.put(key, parameterMap.get(key)[0]);
        }
        return convertParameterMap;
    }
}
